﻿#include <QDebug>

#include <mmdeviceapi.h>
#include <Audioclient.h>
#include <Functiondiscoverykeys_devpkey.h>

#include "WinMediaDevice.h"

#define EXIT_ON_ERROR(hres)  \
    if (FAILED(hres)) { goto Exit; }
#define SAFE_RELEASE(punk)  \
    if ((punk) != NULL)  \
{ (punk)->Release(); (punk) = NULL; }

const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator);
const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);

WinMediaDevice::WinMediaDevice(QObject *parent) : MediaDevice(parent),m_sem(0)
{
}

QList<QPair<QString,QString>> WinMediaDevice::getDeviceList(MediaDeviceType type)
{
    QList<QPair<QString,QString>> list;
    HRESULT hr = S_OK;
    IMMDeviceEnumerator *pEnumerator = NULL;
    IMMDeviceCollection *pCollection = NULL;
    IMMDevice *pEndpoint = NULL;
    IPropertyStore *pProps = NULL;
    LPWSTR pwszID = NULL;

    hr = CoCreateInstance(
                CLSID_MMDeviceEnumerator, NULL,
                CLSCTX_ALL, IID_IMMDeviceEnumerator,
                (void**)&pEnumerator);
    EXIT_ON_ERROR(hr);

    if (type == MediaDeviceType_Input) {
        hr = pEnumerator->EnumAudioEndpoints(
                    eCapture, DEVICE_STATE_ACTIVE,
                    &pCollection);
    } else if (type == MediaDeviceType_Output) {
        hr = pEnumerator->EnumAudioEndpoints(
                    eRender, DEVICE_STATE_ACTIVE,
                    &pCollection);
    }

    EXIT_ON_ERROR(hr);

    UINT  count;
    hr = pCollection->GetCount(&count);
    EXIT_ON_ERROR(hr);

    if (count == 0) {
        qDebug("No endpoints found.\n");
    }

    // Each loop prints the name of an endpoint device.
    for (ULONG i = 0; i < count; i++) {
        // Get pointer to endpoint number i.
        hr = pCollection->Item(i, &pEndpoint);
        EXIT_ON_ERROR(hr)

                // Get the endpoint ID string.
                hr = pEndpoint->GetId(&pwszID);
        EXIT_ON_ERROR(hr)

                hr = pEndpoint->OpenPropertyStore(
                    STGM_READ, &pProps);
        EXIT_ON_ERROR(hr)

                PROPVARIANT varName;
        // Initialize container for property value.
        PropVariantInit(&varName);

        // Get the endpoint's friendly-name property.
        hr = pProps->GetValue(
                    PKEY_Device_FriendlyName, &varName);
        EXIT_ON_ERROR(hr);
        QPair<QString,QString> kv = {QString::fromStdWString(varName.pwszVal),QString::fromStdWString(pwszID)};
        list.push_back(kv);

        CoTaskMemFree(pwszID);
        pwszID = NULL;
        PropVariantClear(&varName);
        SAFE_RELEASE(pProps);
        SAFE_RELEASE(pEndpoint);
    }
    SAFE_RELEASE(pEnumerator);
    SAFE_RELEASE(pCollection);
    return list;
Exit:
    qDebug("Error!\n");
    CoTaskMemFree(pwszID);
    SAFE_RELEASE(pEnumerator);
    SAFE_RELEASE(pCollection);
    SAFE_RELEASE(pEndpoint);
    SAFE_RELEASE(pProps);
    return list;
}

BOOL WinMediaDevice::AdjustFormatTo16Bits(WAVEFORMATEX *pwfx)
{
    BOOL bRet(FALSE);

    if(pwfx->wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
    {
        pwfx->wFormatTag = WAVE_FORMAT_PCM;
        pwfx->wBitsPerSample = 16;
        pwfx->nBlockAlign = pwfx->nChannels * pwfx->wBitsPerSample / 8;
        pwfx->nAvgBytesPerSec = pwfx->nBlockAlign * pwfx->nSamplesPerSec;

        bRet = TRUE;
    }
    else if(pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
    {
        PWAVEFORMATEXTENSIBLE pEx = reinterpret_cast<PWAVEFORMATEXTENSIBLE>(pwfx);
        if (IsEqualGUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, pEx->SubFormat))
        {
            pEx->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;

            pEx->Samples.wValidBitsPerSample = 16;
            pwfx->wBitsPerSample = 16;
            pwfx->nBlockAlign = pwfx->nChannels * pwfx->wBitsPerSample / 8;
            pwfx->nAvgBytesPerSec = pwfx->nBlockAlign * pwfx->nSamplesPerSec;
            bRet = TRUE;
        }
    }

    return bRet;
}

bool WinMediaDevice::isPrepare()
{
    m_sem.acquire();
    return true;
}

bool WinMediaDevice::isSupport(IAudioClient *client,WAVEFORMATEX *pwfx)
{
    return false;
//    int sample = 48000;
//    int channel = 2;
//    int sampleBit = 16;
//    WAVEFORMATEX* wftx = (WAVEFORMATEX*)CoTaskMemAlloc(sizeof(WAVEFORMATEX));
//    wftx->wFormatTag = WAVE_FORMAT_PCM;
//    wftx->nChannels = channel;
//    wftx->nSamplesPerSec = static_cast<DWORD>(sample);
//    wftx->wBitsPerSample = sampleBit;
//    wftx->nAvgBytesPerSec = sample * (sampleBit / 8) * channel;
//    wftx->nBlockAlign = channel * (sampleBit / 8);
//    wftx->cbSize = 0;

//    HRESULT ret = client->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED,wftx,pwfx);
//    if (ret == S_OK) {
//        qDebug() << "support";
//        return true;
//    } else if (ret == S_FALSE && micFormat != NULL){
//        qDebug() << "similar";
//    } else {
//        qDebug() << "unknow";
//    }
//    return false;
}


